﻿//-----------------------------------------------------------------------
// <copyright file="UnitTestShouldNotCallTest.cs" company="COMPANY">
//     Copyright (c) COPYRIGHT. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------

namespace CodeQualityExtension.UnitTestRules
{
    using Microsoft.FxCop.Sdk;
    
    /// <summary>
    /// Checks whether unit tests does not call any other unit test
    /// </summary>
    public class UnitTestShouldNotCallTest : BaseRule
    {
        /// <summary>
        /// Stored currently analyzes test method
        /// </summary>
        private Method analyzedMethod;
        
        /// <summary>
        /// Initializes a new instance of the UnitTestShouldNotCallTest class
        /// </summary>
        public UnitTestShouldNotCallTest()
            : base(typeof(UnitTestShouldNotCallTest))
        { 
        }

        /// <summary>
        /// Checks only externally visible members
        /// </summary>
        public override TargetVisibilities TargetVisibility
        {
            get
            {
                return TargetVisibilities.ExternallyVisible;
            }
        }

        /// <summary>
        /// Calls VisitMethod on all unit test methods
        /// </summary>
        /// <param name="member">FxCop member instance</param>
        /// <returns>Collection of problems</returns>
        public override ProblemCollection Check(Member member)
        {
            Method method = member as Method;
            if (method != null && InternalUtilities.IsTestMethod(method))
            {
                this.analyzedMethod = method;
                VisitMethod(method);
            }
            
            return this.Problems;
        }

        /// <summary>
        /// Creates an analysis problem if there is any call to unit test method within
        /// currently analyzed unit test method.
        /// </summary>
        /// <param name="call">FxCop MethodCall</param>
        public override void VisitMethodCall(MethodCall call)
        {
            MemberBinding memberBinding = call.Callee as MemberBinding;

            if (memberBinding != null)
            {
                Method method = memberBinding.BoundMember as Method;
                if (method != null && InternalUtilities.IsTestMethod(method))
                {
                    // SourceContext enables to display hyperlink to method call
                    Problem problem = new Problem(
                        GetResolution(
                            method.Name.Name, 
                            this.analyzedMethod.Name.Name),
                        call.SourceContext);

                    this.Problems.Add(problem);
                }
            }
            
            base.VisitMethodCall(call);
        }
    }
}
